package com.hhkj.study.common.handler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectResult;
import com.hhkj.study.common.model.res.AliyunOssRes;
import com.ruoyi.common.config.AliYunConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.enums.RRExceptionCodeEnum;
import com.ruoyi.common.exception.GlobalException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.oss.model.AliYunUploadResult;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

@Component
public class AliyunOssUploader {

    @Resource
    private AliYunConfig aliyunOssProperties;

    public OSSClient getOSSClient()
    {
        return new OSSClient(aliyunOssProperties.getOSSEndpoint(),
                aliyunOssProperties.getAccessKeyId(),
                aliyunOssProperties.getAccessKeySecret());
    }

    public AliYunUploadResult uploadMultipartFileToOSS(MultipartFile file, String putKey)
    {
        OSSClient ossClient = getOSSClient();
        PutObjectResult putResult;
        AliYunUploadResult result = new AliYunUploadResult();
        try {
            InputStream inputStream = file.getInputStream();
            // 创建PutObject请求。
            putResult = ossClient.putObject(aliyunOssProperties.getOSSBucketName(), putKey, inputStream);
            result.setPutResult(putResult)
                    .setResultFlag(true);
        } catch (OSSException oe) {
            /*System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());*/
            // TODO: 2022/3/1 记录 OSSException 异常信息，先完成功能，后续开发继续
            result.setResultFlag(false)
                    .setExceptionInfo("上传服务器失败, 请联系管理员");
        } catch (ClientException ce) {
            /*System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());*/
            result.setResultFlag(false)
                    .setExceptionInfo("客户端上传失败, 请联系管理员");
        } catch (IOException e) {
            result.setResultFlag(false)
                    .setExceptionInfo("文件上传失败, 请联系管理员");
        } finally {
            ossClient.shutdown();
        }
        return result;
    }

    public List<AliyunOssRes> uploadAndSaveBatch(List<MultipartFile> fileList) {
        //开启多线程
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //结果集
        List<AliyunOssRes> aliyunOssResultList = new ArrayList<>();
        List<Future<AliyunOssRes>> futureList = fileList.stream()
                .map(file -> executorService.submit(() -> uploadFile(file)))
                .collect(Collectors.toList());
        try {
            while (CollectionUtil.isNotEmpty(futureList)) {
                Iterator<Future<AliyunOssRes>> iterable = futureList.iterator();
                //遍历一遍
                while (iterable.hasNext()) {
                    Future<AliyunOssRes> future = iterable.next();
                    //如果任务完成取结果，否则判断下一个任务是否完成
                    if (future.isDone() && !future.isCancelled()) {
                        //获取结果
                        AliyunOssRes aliyunOssResult = future.get();
                        aliyunOssResultList.add(aliyunOssResult);
                        //任务完成移除任务
                        iterable.remove();
                    } else {
                        Thread.yield();//避免CPU高速运转，这里休息1毫秒，CPU纳秒级别
                    }
                }
            }
        } catch (Exception e) {
            throw new GlobalException(RRExceptionCodeEnum.ALIYUN_OSS_UPLOAD_FAIL.getMessage());
        } finally {
            executorService.shutdown();
        }
        return aliyunOssResultList;
    }

    /**
     * 上传oss 方法
     *
     * @param multipartFile 文件
     * @return 文件上传信息
     */
    public AliyunOssRes uploadFile(MultipartFile multipartFile) {
        // 文件上传到OSS
        String suffix = FileNameUtil.getSuffix(multipartFile.getOriginalFilename());

        // 随机生成文件名称
        String newFileName = UUID.randomUUID().toString() + CharUtil.DOT + suffix;
        String ossPutKey = aliyunOssProperties.getProjectRootFolderName() + getFileDest(suffix) + CharUtil.SLASH + newFileName;
        AliYunUploadResult uploadResult = uploadMultipartFileToOSS(multipartFile, ossPutKey);
        // result.setAliYunUploadResult(uploadResult);

//        AliyunOssUpload ossUploadLogDo
//                = new AliyunOssUpload(
//                uploadResult.isResultFlag() ? CommonConst.FlagEnum.IS.getId() : CommonConst.FlagEnum.NOT.getId(),
//                uploadResult.getExceptionInfo(),
//                ObjectUtil.isNotNull(uploadResult.getPutResult()) ? JSON.toJSONString(uploadResult.getPutResult()) : null,
//                multipartFile.getOriginalFilename(),
//                ossPutKey);
        String fileUrl = aliyunOssProperties.getUrlPrefix() + ossPutKey;
        AliyunOssRes aliyunOssResult = new AliyunOssRes(multipartFile.getOriginalFilename(), fileUrl);

//        // 添加文件上传记录
//        if (uploadResult.isResultFlag()) {
//            // result.setUploadSuccess(true);
//            ossUploadLogDo.setUrl(fileUrl);
//        }
        return aliyunOssResult;
    }


    /**
     * 不同的文件类型返回不同的文件夹
     * @param ext
     * @return
     */
    private String getFileDest(String ext){
        String rootLowerCase = StringUtils.toRootLowerCase(ext);
        if (CollectionUtil.contains(Constants.PIC_EXT_LIST, rootLowerCase)) {
            return "/pic";
        }
        if (CollectionUtil.contains(Constants.DOC_EXT_LIST, rootLowerCase)) {
            return "/doc";
        }
        return "";
    }
}
